package com.NetSunWeiQin.chapter03.multithread4;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;


/**
 * 带控制命令的 echoServer ....
 */
public class ControlledEchoServer {
    private static final int port = 8000;
    private ServerSocket serverSocket;
    private ExecutorService executorService;
    private static final int POOL_SIZE = 1;

    private static final int portForShutdown = 8001;
    private ServerSocket serverSocketForShutdown;
    private boolean isShutdown = false;

    private Thread shutdownThread = new Thread("命令监听线程") {

        @Override
        public void start() {
            super.start();
        }


        @Override
        public void run() {
            System.out.println("command  listener  start.......    ");
            Socket socketForShutdown = null;
            BufferedReader br= null;
            try {
                socketForShutdown = serverSocketForShutdown.accept();
                br = new BufferedReader(new InputStreamReader(socketForShutdown.getInputStream()));
            } catch (IOException e) {
                e.printStackTrace();
            }


            while (!isShutdown) {

                try {
                    sleep(1000);

                    String command = br.readLine();
                    if (command != null && command.length() != 0 && !command.equals("null")) {
                        System.out.println(Thread.currentThread().getName() + "==>  " + command);
                    }
                    if (command.contains("shutdown")) {
                        long beginTime = System.currentTimeMillis();
                        socketForShutdown.getOutputStream().write("server shutdown......  \r\n".getBytes());
                        isShutdown = true;
                        executorService.shutdown();
                        while (!executorService.isTerminated()) {
                            executorService.awaitTermination(30, TimeUnit.SECONDS);
                        }
                        serverSocket.close();

                        long endTime = System.currentTimeMillis();

                        socketForShutdown.getOutputStream().write(("server has been already shutdown..." + " use " + (endTime - beginTime) + "ms  \r\n").getBytes());

                        socketForShutdown.close();
                        serverSocketForShutdown.close();
                        System.out.println("server shutdown ");
                    } else {
                        if (command != null && command.length() != 0 && !command.equals("null")) {
                            socketForShutdown.getOutputStream().write(("wrong  command... " + command + " \r\n").getBytes());
                        }
                        //socketForShutdown.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    };

    protected ControlledEchoServer() throws IOException {
        serverSocket = new ServerSocket(port);
        serverSocket.setSoTimeout(60000);
        serverSocketForShutdown = new ServerSocket(portForShutdown);
        executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_SIZE);  //使用线程池
        shutdownThread.start();                             //启动 命令线程.........
        System.out.println("server started.....");
    }

    protected void service() {
        System.out.println("service start............");
        while (!isShutdown) {
            Socket socket = null;
            try {
                socket = serverSocket.accept();
                socket.setSoTimeout(60000);
                executorService.execute(new Handler(socket));
            } catch (SocketTimeoutException e) {

            } catch (RejectedExecutionException e) {
                try {
                    if (socket != null) socket.close();
                } catch (IOException x) {
                }
                return;
            } catch (SocketException e) {


                if (e.getMessage().contains("socket closed")) return;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String args[]) throws IOException {
        new ControlledEchoServer().service();
    }
}

class Handler implements Runnable {
    private Socket socket;

    protected Handler(Socket socket) {
        this.socket = socket;
    }

    private PrintWriter getWriter(Socket socket) throws IOException {
        OutputStream socketOut = socket.getOutputStream();
        return new PrintWriter(socketOut, true);
    }

    private BufferedReader getReader(Socket socket) throws IOException {
        InputStream socketIn = socket.getInputStream();
        return new BufferedReader(new InputStreamReader(socketIn));
    }

    protected String echo(String msg) {
        return "echo:" + msg;
    }

    public void run() {
        try {
            System.out.println("New connection accepted " + socket.getInetAddress() + ":" + socket.getPort());
            BufferedReader br = getReader(socket);
            PrintWriter pw = getWriter(socket);

            String msg;
            while ((msg = br.readLine()) != null) {
                System.out.println("from " + socket.getInetAddress()+ ":" + socket.getPort() + ">" + msg);
                pw.println(echo(msg));
                if (msg.equals("bye"))
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (socket != null) socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}


